package com.simen.hellobytes.socket;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 以太网和IPv4网都用全1的地址表示广播，分别是ff:ff:ff:ff:ff:ff和255.255.255.255。
 * 令牌环网络使用IEEE 802.2控制域中的一个特殊值来表示广播。
 * @author Created by Simen.
 * @date 创建日期 2018/5/9 10:59
 * @modify 修改者 Simen
 */
public class UDPBroadcastClient {

    private static final String DEFAULT_BROADCAST_IP = "255.255.255.255";
    private static final int PORT = 15103;

    private DatagramSocket ds = null;
    private boolean isRunning = false;

    private String broadcastIp;
    private int broadcastPort = PORT;
    private byte[] messageBytes;

    public UDPBroadcastClient() {

    }

    public UDPBroadcastClient(byte[] messageBytes) {
        this.messageBytes = messageBytes;
    }

    public UDPBroadcastClient(int broadcastPort) {
        this.broadcastPort = broadcastPort;
    }

    public UDPBroadcastClient(String broadcastIp) {
        this.broadcastIp = broadcastIp;
    }

    public UDPBroadcastClient(String broadcastIp, int broadcastPort) {
        this.broadcastIp = broadcastIp;
        this.broadcastPort = broadcastPort;
    }

    public void sendBroadcast() {
        isRunning = true;

        if(messageBytes!=null) {
            String[] broadcastIps = null;

            try {
                broadcastIps = IpUtil.getBroadcastAddress();
            } catch (SocketException e) {
                e.printStackTrace();
            }

            if (broadcastIp == null) {
                if (broadcastIps == null || broadcastIps.length == 0) {
                    broadcastIp = DEFAULT_BROADCAST_IP;
                    sendBroadcastImpl();
                    return;
                }

                for (int i = 0; isRunning && i < broadcastIps.length; i++) {
                    broadcastIp = broadcastIps[i];

                    sendBroadcastImpl();
                }
            } else {
                sendBroadcastImpl();
            }
        }

        isRunning = false;
    }

    private void sendBroadcastImpl() {
        try {
            ds = new DatagramSocket();
            DatagramPacket dp = new DatagramPacket(
                    messageBytes,
                    messageBytes.length,
                    InetAddress.getByName(broadcastIp),
                    broadcastPort
            );
            ds.setBroadcast(true);
            ds.send(dp);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeImmediately();
        }
    }

    public void setMessageBytes(byte[] messageBytes) {
        this.messageBytes = messageBytes;
    }

    public boolean isRunning() {
        return isRunning;
    }

    public void setRunning(boolean running) {
        isRunning = running;
    }

    public void closeImmediately() {
        if (ds != null) {
            ds.close();
            ds = null;
        }
    }

}
